import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import { db } from '../config/database';
import logger from '../utils/logger';

// 扩展 Request 类型
declare global {
  namespace Express {
    interface Request {
      user?: {
        userId: string;
        email: string;
        plan: string;
        credits?: number;
      };
    }
  }
}

/**
 * 认证中间件
 * 验证JWT token并设置user信息到request对象
 */
export const authenticate = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
  try {

    // 获取Authorization header
    const authHeader = req.headers.authorization;

    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      res.status(401).json({
        success: false,
        message: '缺少认证令牌',
      });
      return;
    }

    // 提取token
    const token = authHeader.substring(7); // 移除 "Bearer " 前缀

    // 验证token
    const jwtSecret = process.env.JWT_ACCESS_SECRET || 'your-secret-key';
    let decoded: any;

    try {
      decoded = jwt.verify(token, jwtSecret);
    } catch (jwtError: any) {
      logger.warn('JWT验证失败:', jwtError.message);
      res.status(401).json({
        success: false,
        message: '无效的认证令牌',
      });
      return;
    }

    // 检查token是否在黑名单中
    const redis = await db.redis();

    const promises = [
      redis.get(`blacklist:token:${token}`),
      redis.get(`session:user:${decoded.userId}`),
    ]

    const [isBlacklisted, sessionData] = await Promise.all(promises);

    if (isBlacklisted) {
      res.status(401).json({
        success: false,
        message: '认证令牌已失效',
      });
      return;
    }

    if (!sessionData) {
      res.status(401).json({
        success: false,
        message: '会话已过期，请重新登录',
      });
      return;
    }

    const session = JSON.parse(sessionData);

    // 检查用户状态
    if (!session.isActive) {
      res.status(401).json({
        success: false,
        message: '账户已被禁用',
      });
      return;
    }


    req.user = session;
    
    next();
  } catch (error: any) {
    logger.error('认证中间件错误:', error);
    res.status(500).json({
      success: false,
      message: '认证过程出错',
    });
  }
};

/**
 * 可选认证中间件
 * 如果有token则验证，没有则继续执行
 */
export const optionalAuth = async (req: Request, res: Response, next: NextFunction) => {
  try {
    const authHeader = req.headers.authorization;

    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      return next(); // 没有token，继续执行
    }

    // 尝试认证，但不阻止请求
    await authenticate(req, res, (error?: any) => {
      if (error) {
        // 认证失败也继续执行，但清除用户信息
        req.user = undefined;
      }
      next();
    });
  } catch (error: any) {
    logger.error('可选认证中间件错误:', error);
    req.user = undefined;
    next();
  }
};

/**
 * 权限检查中间件（根据用户计划）
 */
export const checkPlan = (requiredPlan: 'FREE' | 'PRO' | 'BUSINESS') => {
  return (req: Request, res: Response, next: NextFunction): void => {
    const user = req.user;

    if (!user) {
      res.status(401).json({
        success: false,
        message: '需要登录才能访问此功能',
      });
      return;
    }

    const planLevels = { 'FREE': 0, 'PRO': 1, 'BUSINESS': 2 };
    const userLevel = planLevels[user.plan as keyof typeof planLevels] ?? 0;
    const requiredLevel = planLevels[requiredPlan];

    if (userLevel < requiredLevel) {
      res.status(403).json({
        success: false,
        message: `需要 ${requiredPlan} 计划才能访问此功能`,
        data: {
          currentPlan: user.plan,
          requiredPlan: requiredPlan,
        },
      });
      return;
    }

    next();
  };
};

/**
 * 积分检查中间件
 */
export const checkCredits = (requiredCredits: number) => {
  return (req: Request, res: Response, next: NextFunction): void => {
    const user = req.user;

    if (!user) {
      res.status(401).json({
        success: false,
        message: '需要登录才能访问此功能',
      });
      return;
    }

    if (!user.credits || user.credits < requiredCredits) {
      res.status(403).json({
        success: false,
        message: '积分不足',
        data: {
          currentCredits: user.credits || 0,
          requiredCredits: requiredCredits,
        },
      });
      return;
    }

    next();
  };
};
